#include "loop.h"
#include "object.h"
#include "face.h"
#include "vertex.h"
#include "vector3d.h"

Loop::Loop(int _id, Face *_f, HalfEdge *_he) : id(_id), face(_f), heRing(_he){}

Vector3D Loop::normal() const
{
    /**
        pegar a normal usando os 3 primeiros pontos do loop
    */
//    Vector3D p1 = heRing->getVertex()->getPosition();
//
//    HalfEdge *he2 = heRing->getNext();
//    Vector3D p2 = he2->getVertex()->getPosition();
//    if(p1 == p2) std::cout << "Tentando pegar a normal de um loop com uma half-edge (ou dois pontos iguais)" << std::endl;
//
//    HalfEdge *he3 = he2->getNext();
//    Vector3D p3 = he3->getVertex()->getPosition();
//    if(p1 == p3) std::cout << "Tentando pegar a normal de um loop com somente duas half-edges (ou dois pontos iguais)" << std::endl;

    Vector3D p1, p2, p3;
    HalfEdge *he = heRing;
    unsigned int test = 0;
    unsigned int totalVertex = face->getObject()->getVerticesSize();

    do
    {
        p1 = he->getVertex()->getPosition();
        p2 = he->getNext()->getVertex()->getPosition();
        p3 = he->getNext()->getNext()->getVertex()->getPosition();

        if (test > totalVertex)
        {
            std::cout << "A face é toda colinear" << std::endl;
//            std::cout << "test " << test << "\t\ttotalVertex " <<totalVertex  << std::endl;
//
//
//            std::cout << "P1" << std::endl;
//    p1.print();
//            std::cout << "P2" << std::endl;
//    p2.print();
//            std::cout << "P3" << std::endl;
//    p3.print();
            return Vector3D(0, 0, 1);
        }

        test++;
        he = he->getNext();
    }while (isCollinear( p2 - p1, p3 - p1 ));
//            std::cout << "SAIU!   - " << test << std::endl;
//    p1.normal(p2, p3).print();
    return p1.normal(p2, p3);
}

double Loop::area() const
{
    /**
        calcular a area
    */
    double result = 0;

    HalfEdge *he1 = heRing;             //começa com o iniciodo loop
    HalfEdge *he2 = he1->getNext();     //pega o proximo
    if(he1 == he2) std::cout <<"Tentando calcular a área de um loop com uma half-edge" << std::endl;

    Vector3D p = he1->getVertex()->getPosition();   //guarda a primeira posição

    Vector3D p1, p2;                                //guadas as outras posições do triangulo
    do{
        p1 = he2->getVertex()->getPosition();               //pega o proximo ponto
        p2 = he2->getNext()->getVertex()->getPosition();    //pega o proximo do proximo ponto
        result += p.area(p1, p2);                           //calcula a area do triangulo

        he2 = he2->getNext();                               //anda no loop
    }while(he1 != he2->getNext());                          //para quando acabar o loop

    return result;
}

//void Loop::translate(const Vector3D &_t)
//{
//
//    HalfEdge *he1 = heRing; //pega o inicio do loop
//    HalfEdge *he2 = heRing; //ponteiro que será usado para andar no loop, começa com o inicio
//
//    Vertex *v;
//    do{
//        v = he2->getVertex();       //pega o vertice da half-edge corrente
//        v->translate(_t);        //translada
//
//        he2 = he2->getNext();       //anda no loop
//    }while(he1 != he2);
//}

std::set<Vertex *> Loop::getVertices()
{
    std::set<Vertex *> result;

    HalfEdge *he1 = heRing; //pega o inicio do loop
    HalfEdge *he2 = heRing; //ponteiro que será usado para andar no loop, começa com o inicio

    Vertex *v;
    do{
        v = he2->getVertex();       //pega o vertice da half-edge corrente
        result.insert(v);

        he2 = he2->getNext();       //anda no loop
    }while(he1 != he2);

    return result;
}

void Loop::setColor(const Color &_color)
{
    /**
        muda a cor de todos os vertices
    */

    HalfEdge *he1 = heRing; //pega o inicio do loop
    HalfEdge *he2 = heRing; //ponteiro que será usado para andar no loop, começa com o inicio

    Vertex *v;
    do{
        v = he2->getVertex();       //pega o vertice da half-edge corrente
        v->setColor(_color);        //muda a cor

        he2 = he2->getNext();       //anda no loop
    }while(he1 != he2);
}


void Loop::selectAdjacentVertex()
{
    HalfEdge *scan = heRing;
    do{
        Vertex *v = scan->getVertex();
        v->select(true);

        scan = scan->getNext();
    }while( scan != heRing );
}

void Loop::selectAdjacentEdge()
{
    HalfEdge *scan = heRing;
    do{
        Edge *e = scan->getEdge();
        e->select(true);

        scan = scan->getNext();
    }while( scan != heRing );
}

void Loop::selectAdjacentFace()
{
    HalfEdge *scan = heRing;
    do{
        Face *e = scan->getTwin()->getLoop()->getFace();
        e->select(true);

        scan = scan->getNext();
    }while( scan != heRing );
}
